🌱 Add e2e regression test for cross-CE collision protection#2783
🌱 Add e2e regression test for cross-CE collision protection#2783perdasilva wants to merge 1 commit into
Conversation
✅ Deploy Preview for olmv1 ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
There was a problem hiding this comment.
Pull request overview
Adds an end-to-end regression scenario to ensure cross-ClusterExtension “collision protection” works (a second ClusterExtension targeting an already-installed bundle cannot take over resources), and extends the godog step library to make multi-CE assertions readable and robust.
Changes:
- Adds a new e2e scenario covering duplicate ClusterExtension installs and verifies original ownership is retained.
- Extends step definitions with named ClusterExtension condition assertions, a ClusterObjectSet ownership-count assertion, and a
${PREV_NAME}template variable to reference a previously-applied CE. - Refactors message-fragment matching into a shared helper and changes template expansion to preserve unknown
${KEY}variables literally.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| test/e2e/steps/steps.go | Adds named CE steps, COS ownership-count step, ${PREV_NAME} support, message-fragment helper, and preserves unresolved template variables. |
| test/e2e/steps/hooks.go | Extends scenario context to track previousClusterExtensionName. |
| test/e2e/features/update.feature | Adds a new regression scenario validating cross-CE collision protection behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
943273a to
a29cdef
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2783 +/- ##
==========================================
+ Coverage 70.40% 70.50% +0.09%
==========================================
Files 143 143
Lines 10617 10617
==========================================
+ Hits 7475 7485 +10
+ Misses 2580 2573 -7
+ Partials 562 559 -3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
| And ClusterExtension is rolled out | ||
| And ClusterExtension is available | ||
| And ClusterExtension "${NAME}" owns 1 ClusterObjectSet | ||
| And the current ClusterExtension is tracked for cleanup |
There was a problem hiding this comment.
I would perhaps replace this with:
ClusterExtension "${NAME}" is tracked for cleanup
btw, I am not sure what does it mean from user perspective and if users need to know anything about it? Is that an implementation detail?
There was a problem hiding this comment.
Removed this step entirely. ResourceIsApplied now auto-tracks every applied ClusterExtension for cleanup via addedResources, so there's no need for a manual tracking step. The previousClusterExtensionName / ${PREV_NAME} machinery has also been removed.
| matchLabels: | ||
| "olm.operatorframework.io/metadata.name": ${CATALOG:test} | ||
| """ | ||
| Then ClusterExtension "${NAME}" reports Progressing as True with Reason Retrying and Message includes: |
There was a problem hiding this comment.
I assume ${NAME}-dup should report Progressing, not the already installed CE ${NAME}?
There was a problem hiding this comment.
Fixed. Both collision scenarios now use explicit names — ce-orig-${SCENARIO_ID} for the original CE and ce-dup-${SCENARIO_ID} for the duplicate — so every assertion unambiguously identifies which CE it checks. No more implicit ${NAME} context switching.
| """ | ||
| Then ClusterExtension "${NAME}" reports Progressing as True with Reason Retrying and Message includes: | ||
| """ | ||
| revision object collisions |
There was a problem hiding this comment.
can we make this message clearer to users, as we discussed in the original PR?
There was a problem hiding this comment.
The test asserts a substring match against what the controller actually emits — revision object collisions is the literal message from the ClusterObjectSet reconciler (setRetryingConditions in clusterobjectset_controller.go). Changing the wording would be a controller code change rather than a test change. Happy to open a follow-up to improve the message if you have a suggestion for clearer wording.
| """ | ||
| revision object collisions | ||
| """ | ||
| And ClusterExtension "${PREV_NAME}" reports Installed as True |
There was a problem hiding this comment.
it should be actually
ClusterExtension "${NAME}" reports Installed as True
because this is the one first installed/created in this scenario?
There was a problem hiding this comment.
Fixed — now explicitly ClusterExtension "ce-orig-${SCENARIO_ID}" reports Installed as True. Both CEs are referenced by their explicit names throughout the scenario.
| revision object collisions | ||
| """ | ||
| And ClusterExtension "${PREV_NAME}" reports Installed as True | ||
| # Update the conflicting ClusterExtension with a deployment config env var. At the time |
There was a problem hiding this comment.
are we updating here ${NAME} or ${NAME}-dup?
There was a problem hiding this comment.
Fixed — the YAML now explicitly says name: ce-dup-${SCENARIO_ID} and the comment reads "Update the duplicate ClusterExtension with a deployment config env var to force a second revision."
| "olm.operatorframework.io/metadata.name": ${CATALOG:test} | ||
| """ | ||
| Then ClusterExtension "${NAME}" owns 2 ClusterObjectSets | ||
| And ClusterExtension "${NAME}" reports Progressing as True with Reason Retrying and Message includes: |
There was a problem hiding this comment.
Fixed — now explicitly ClusterExtension "ce-dup-${SCENARIO_ID}" throughout.
| """ | ||
| revision object collisions | ||
| """ | ||
| And ClusterExtension "${PREV_NAME}" reports Installed as True |
There was a problem hiding this comment.
how do we know that 2nd ClusterObjectSet is installed successfully?
There was a problem hiding this comment.
The test intentionally verifies that the duplicate CE cannot install — both its revisions collide with the original CE's objects. The assertions confirm this:
ce-dupowns 2 ClusterObjectSets → revision 2 was createdce-dupreports Progressing/Retrying with "revision object collisions" → both revisions are blockedce-origreports Installed=True → the original CE is unaffected
I initially considered using the progression deadline timeout to verify the dup CE settles into a terminal failure state, but it started adding too much complexity and wait time for what is fundamentally a regression test. Would there be a better signal we could use here? For example, would asserting the dup stays in Retrying for 30s–60s be sufficient, or is there a cleaner way to verify the collision is persistent?
- Add e2e tests verifying that a second ClusterExtension targeting an
already-installed bundle cannot take over resources from the original
owner, even with a higher-revision ClusterObjectSet.
- Use explicit CE names (ce-orig-${SCENARIO_ID}, ce-dup-${SCENARIO_ID})
in collision scenarios so every assertion unambiguously identifies
which ClusterExtension it checks.
- Auto-track every applied ClusterExtension for cleanup in
ResourceIsApplied, eliminating the manual
TrackCurrentClusterExtensionForCleanup step and the
previousClusterExtensionName / ${PREV_NAME} machinery.
- Add named CE condition steps (NamedClusterExtensionReportsCondition,
NamedClusterExtensionReportsConditionWithMessageFragment) so step
descriptions explicitly identify which CE is being asserted.
- Add ClusterExtensionOwnsClusterObjectSets step to verify the number
of ClusterObjectSets owned by a named CE.
- Extract messageFragmentComparison helper to deduplicate the
fragment-matching closure across condition steps.
- Preserve unresolved template variables as literal ${KEY} instead of
silently substituting empty string.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
a29cdef to
f79695c
Compare
| if res.GetKind() == "ClusterExtension" { | ||
| sc.clusterExtensionName = res.GetName() | ||
| sc.addedResources = append(sc.addedResources, resource{name: res.GetName(), kind: "clusterextension"}) | ||
| } else if res.GetKind() == "ClusterObjectSet" { |
Summary
ce-orig-${SCENARIO_ID},ce-dup-${SCENARIO_ID}) in collision scenarios so every assertion unambiguously identifies which ClusterExtension it checks.ResourceIsApplied, eliminating the manualTrackCurrentClusterExtensionForCleanupstep and thepreviousClusterExtensionName/${PREV_NAME}machinery.NamedClusterExtensionReportsCondition,NamedClusterExtensionReportsConditionWithMessageFragment) so step descriptions explicitly identify which CE is being asserted.ClusterExtensionOwnsClusterObjectSetsstep to verify the number of ClusterObjectSets owned by a named CE.messageFragmentComparisonhelper to deduplicate the fragment-matching closure across condition steps.${KEY}instead of silently substituting empty string.Test plan
go vetpasses🤖 Generated with Claude Code